# 1 引言 虽然现在 Css Module 与 Css-in-js 更流行,但使用它们会导致过分依赖 **滥用 class 做唯一定位**,违背了 Css 选择器的初衷。 本期精读的文章是:[attribute-selectors-splicing-html-dna-css](https://www.smashingmagazine.com/2018/10/attribute-selectors-splicing-html-dna-css/),带你重新理解强大的 Css 选择器。 # 2 概要 Css Module 与 Css-in-js 大部分场景使用 className 作为选择器,那么本文以选择器为重点,看看选择器有哪些实用的用法。 ## 属性选择器 如果你想选择包含 `title` 属性的 `div`: ```css div[title] ``` 选择包含 `title` 属性的子元素,只需要加个空格: ```css div [title] ``` 选择 `title` 内容是 `dna` 的元素: ```css div[title="dna"] ``` 选择 `title` 属性包含 `dna` 单词的元素: > 注意 dna 需要是单词,也就是用空格分割,比如 “my beautiful dna” 或 “mutating dna is fun!” ```css div[title~="dna"] ``` 和正则类似,选择 `title` 属性中,以 `dna` 结尾的元素: ```css div[title$="dna"] ``` 以 `dna` 开头: ```css div[title^="dna"] ``` 如果希望选择 `dna` 或 `dna-zh`,但不希望匹配 `dnaer`,可以: > 这种场景一般用在国际化,比如 en en-us 就可以用 `|="en"` ```css div[title|="dna"] ``` 只要包含 `dna` 这三个字符就选中: ```css div[title*="dna"] ``` 真的很像正则,你可以用 `i` 标识匹配时大小写不敏感: ```css div[title*="dna" i] ``` 如果你想找到一个 `a` 标签,拥有 `title` 属性并且 className 以 `genes` 结尾,可以这样: ```css a[title][class$="genes"] ``` ## 获取标签的值 可以用 `attr` 标识符拿到当前选择器选中元素的属性,比如当 `hover` 状态时,在文字尾部显示其 `title` 属性: ```css .joke:hover:after { content: "Answer:" attr(title); display: block; } ``` ## 其它用法 本文还介绍了一些实用技巧,比如 **根据输入框类型设置样式** ```css input[type="email"] { color: papayawhip; } input[type="tel"] { color: thistle; } ``` **改变下载标签的 icon** ```css a[download][href$="pdf"]:after { content: url(pdf-icon.svg); } ``` 当然也可以选中一些老代码进行样式重写,比如: ```html
Old, holey genes
``` ```css div[bgcolor="#000000"] { /*override*/ background-color: #222222 !important; } ``` 不过这种用法要谨慎,写的越多越难以维护。 **结合一些新标签功能** 比如 `details` 标签是 html 原生的手风琴折叠组件: ```html
List of Genes Roddenberry Hackman
``` 我们可以使用属性选择器,定义其打开时的样式: ```css details[open] { background-color: hotpink; } ``` **为没有 `async` 标记的 `script` 标签着色**,算是友情提示哪儿有错误: ```css script[src]:not([async]) { display: block; width: 100%; height: 1em; background-color: red; } script:after { content: attr(src); } ``` **为 JS 事件着色**,比如触发的鼠标事件可以作为选择器: ```css [OnMouseOver] { color: burlywood; } [OnMouseOver]:after { content: "JS: " attr(OnMouseOver); } ``` **选中隐藏元素:** ```css [hidden], [type="hidden"] { display: block; } ``` 还有更多就不一一列举了,感兴趣的读者可以跳转到原文继续阅读。大部分内容其实都写在了 [w3school 选择器参考手册](http://www.w3school.com.cn/cssref/css_selectors.asp),只是结合一篇文章来读,可以理解得更深刻,同时文章里确实有一些新鲜的选择器,比如 JS 事件选择器,HTML5 属性标签选择器等等。 # 3 精读 这篇文章确实说明了 Css 选择器的强大性,但回到 css module 或者 css-in-js 的工程代码里,我们往往难以做太多的实践,有如下几个原因: ## 一直在担心的 DOM 结构变动 业务开发中,大量需求涌入,也许过了一周,DOM 结构就已经面目全非了,而且就算是一个普通的圣杯布局,可能老版本用 Table 布局,后面进来一个年轻小伙子直接用 div + flex 重构了,你会担心之前写的 table 选择器在某一天全部失效。 也许今天的 div 选择器,明天因为语义化改造就换成了 article 标签。 最大原因是 **一种视觉界面对应的实现方式太多**,不仅标签可以各异,css 属性还有 table、block、flex、grid 可选,同时 grid 属性还会导致视觉结构与 DOM 结构不完全对应。 如果你今天用 css 选择器做了一套完全贴合现在 DOM 结构的 css 文件,这个 css 文件也许是后面 dom 结构改动的噩梦。 ## 你敢做全局样式覆盖吗 我们排除标签,仅对属性做全局覆盖,的确可以部分绕开 DOM 结构的限制,但是这样的全局样式覆盖,不同的人有不同看法。 小明的团队非常懂得 css 运用,他们每天都会花一个小时讨论项目的 css 架构,并对通用需求样式做了抽象,并且每个人都很认可这个方案,在他们的团队,一个非常酷炫的按钮与动画效果,通过 `